#ifndef CONF_ELEMENT_H_
#define CONF_ELEMENT_H_

#include "attribute.h"
#include "parser.h"
#include "writer.h"

namespace gpyp {
namespace conf {

class Element;
typedef boost::shared_ptr<Element> RefElement;
class Document;

class Element : public Node {
  friend class ConfParser;
public:
  typedef std::list<RefElement> ElementList;
  typedef std::list<RefAttributeBase> AttributeList;

private:
  sigc::signal<void> signal_presave_;
public:
  inline sigc::signal<void> signal_presave() {
    return signal_presave_;
  }

private:
  bool   loaded_;
  size_t element_depth_;

  ElementList   elements_;
  AttributeList attributes_;

protected:
  inline size_t get_element_depth() const {
    return element_depth_;
  }

  virtual void on_preload();
  virtual void on_load(ConfParser  &parser,
                       const char  *element_name,
                       const char **attribute_names,
                       const char **attribute_values);
  virtual void on_start_element(ConfParser  &parser,
                                const char  *element_name,
                                const char **attribute_names,
                                const char **attribute_values,
                                GError     **error);
  virtual void on_end_element(ConfParser &parser,
                              const char *element_name,
                              GError    **error);
  virtual void on_postload();
  virtual void on_load_default();
  virtual void on_default_loaded();

  virtual void on_presave();
  virtual void on_save(Writer &writer, bool force);
  virtual void on_save_attributes(Writer &writer, bool force);
  virtual void on_save_contents(Writer &writer, bool force);
  virtual bool on_get_has_contents(bool force) const;

  virtual bool on_get_dirty() const;
  virtual void on_set_dirty(bool dirty);

private:
  template<typename R, typename T>
  inline R run_func_by_node(boost::shared_ptr<T> node,
                            R (Element::*f_e)(RefElement element),
                            R (Element::*f_a)(RefAttributeBase attribute)) {
    RefElement element = boost::dynamic_pointer_cast<Element>(node);
    if (element) return (this->*f_e)(element);

    RefAttributeBase attribute =
      boost::dynamic_pointer_cast<AttributeBase>(node);
    if (attribute) return (this->*f_a)(attribute);
  }

public:
  void add_element(RefElement element);
  void add_attribute(RefAttributeBase attribute);

  void remove_element(RefElement element);
  void remove_attribute(RefAttributeBase attribute);

  template<typename T>
  inline void add(boost::shared_ptr<T> node) {
    run_func_by_node<void>(node,
                           &Element::add_element,
                           &Element::add_attribute);
  }
  template<typename T>
  inline void remove(boost::shared_ptr<T> node) {
    run_func_by_node<void>(node,
                           &Element::remove_element,
                           &Element::remove_attribute);
  }

  inline const ElementList get_elements() const {
    return elements_;
  }
  inline const AttributeList get_attributes() const {
    return attributes_;
  }

  Element(const Glib::ustring &name);
};

}/*conf*/
}/*gpyp*/

#endif/*CONF_ELEMENT_H_*/
